package com.xwder.netty.simple;

import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.Channel;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandlerAdapter;
import io.netty.channel.ChannelPipeline;
import io.netty.util.CharsetUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.concurrent.TimeUnit;

/**
 * 1.我们自定义一个Handler 需要继续netty 规定好的某个HandlerAdapter(规范)
 * 2.这时我们自定义一个Handler , 才能称为一个handler
 *
 * @author xwder
 * @date 2021/3/22 09:48
 **/
public class NettyServerHandler extends ChannelInboundHandlerAdapter {

    private static final Logger logger = LoggerFactory.getLogger(NettyServerHandler.class);

    /**
     * 读取数据实际(这里我们可以读取客户端发送的消息)
     *
     * @param ctx 上下文对象, 含有 管道pipeline , 通道channel, 地址
     * @param msg 就是客户端发送的数据 默认Object
     */
    @Override
    public void channelRead(ChannelHandlerContext ctx, Object msg) {
        // 比如这里我们有一个非常耗时长的业务-> 异步执行 -> 提交该channel 对应的 NIOEventLoop 的 taskQueue中NIOEventLoop 的 taskQueue中
        // 两种解决方案：方案一：用户程序自定义的普通任务，方案二： 用户自定义定时任务 -》 该任务是提交到 scheduleTaskQueue中

        // 方案一：用户程序自定义的普通任务
        ctx.channel().eventLoop().execute(new Runnable() {
            @Override
            public void run() {
                try {
                    Thread.sleep(5 * 1000);
                    ctx.writeAndFlush(Unpooled.copiedBuffer("hello, 客户端~(>^ω^<)喵2 ~~~", CharsetUtil.UTF_8));
                    logger.info("netty server channel hashCode:{}", ctx.channel().hashCode());
                } catch (InterruptedException e) {
                    logger.error("netty server error", e);
                }
            }
        });

        ctx.channel().eventLoop().execute(new Runnable() {
            @Override
            public void run() {
                try {
                    Thread.sleep(5 * 1000);
                    ctx.writeAndFlush(Unpooled.copiedBuffer("hello, 客户端~(>^ω^<)喵3 ~~~", CharsetUtil.UTF_8));
                    logger.info("netty server channel hashCode:{}", ctx.channel().hashCode());
                } catch (InterruptedException e) {
                    logger.error("netty server error", e);
                }
            }
        });

       // 方案二：用户自定义定时任务 -》 该任务是提交到 scheduleTaskQueue中
        ctx.channel().eventLoop().schedule(new Runnable() {
            @Override
            public void run() {
                try {
                    Thread.sleep(10 * 1000);
                    ctx.writeAndFlush(Unpooled.copiedBuffer("hello, 客户端~(>^ω^<)喵4 ~~~", CharsetUtil.UTF_8));
                    logger.info("netty server channel hashCode:{}", ctx.channel().hashCode());
                } catch (InterruptedException e) {
                    logger.error("netty server error", e);
                }
            }
        }, 5, TimeUnit.SECONDS);

        Channel channel = ctx.channel();
        ChannelPipeline pipeline = ctx.pipeline();

        ByteBuf byteBuf = (ByteBuf) msg;
        logger.info("服务器读取线程：{},channel:{},server ctx:{}", Thread.currentThread().getName(), ctx.channel(), ctx);
        logger.info("客户端地址:{},发送的消息内容是：{}", channel.remoteAddress(), byteBuf.toString(CharsetUtil.UTF_8));
    }

    /**
     * 读取数据完毕
     *
     * @param ctx 上下文对象, 含有 管道pipeline , 通道channel, 地址
     */
    @Override
    public void channelReadComplete(ChannelHandlerContext ctx) {
        ctx.writeAndFlush(Unpooled.copiedBuffer("hello, 客户端~(>^ω^<)喵1 ~~~", CharsetUtil.UTF_8));
    }

    /**
     * 处理异常, 一般是需要关闭通道
     *
     * @param ctx   上下文对象, 含有 管道pipeline , 通道channel, 地址
     * @param cause 异常信息
     */
    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {
        ctx.close();
    }
}
